package com.xhl.consul.tool.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.MediaType;
import org.springframework.mock.web.server.MockWebSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @Author CazCen
 * @Date 2021/11/26 13:53
 */
@Api(tags = "Mono测试")
@RestController
@RequestMapping("/test/mono")
@Slf4j
public class MonoController {

    @PostMapping("/hello")
    @ApiOperation("Optional测试")
    public Optional<String> hello(@RequestParam(required = false) String str){
        if(StringUtils.isEmpty(str)){
            return Optional.empty();
        }
        Optional<String> s = Optional.of("业余草：www.xttblog.com");
        String s1 = s.get();
        log.info("s1:{}",s1);
        return Optional.of("业余草：www.xttblog.com");
    }

    @PostMapping(value = "/mono")
    @ApiOperation("Mono测试")
    public Mono<String> mono(@RequestParam(required = false) String str){
        if(StringUtils.isEmpty(str)){
            return Mono.empty();
        }

        Mono<String> just = Mono.just("业余草：www.xttblog.com");
        return Mono.just("业余草：www.xttblog.com");
    }



    // 阻塞5秒钟
    private String createStr() {
        try {
            TimeUnit.SECONDS.sleep(30);
        } catch (InterruptedException e) {
        }
        return "some string";
    }

    // 普通的SpringMVC方法
    @GetMapping("/get1")
    @ApiOperation("get1 测试")
    private String get1() {
        log.info("get1 start");
        String result = createStr();
        log.info("get1 end.");
        return result;
    }

    // WebFlux(返回的是Mono)
    @GetMapping("/get2")
    @ApiOperation("get2 测试")
    private Mono<String> get2() {
        log.info("get2 start");
        Mono<String> result = Mono.fromSupplier(() -> createStr());
        log.info("get2 end.");
        return result;
    }



    /**
     * Flux : 返回0-n个元素
     * 注：需要指定MediaType
     * @return
     */
    @GetMapping(value = "/flux3", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiOperation("flux3 测试")
    private Flux<String> flux() {
        Flux<String> result =
                Flux.fromStream(IntStream.range(1, 5).mapToObj(i -> {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    log.info("23122344324");
                    return "flux data--" + i;
                }));

        // Flux 里面是个stream，而 Flux.subscribe 里面会使用stream，stream 有一个特点就是一次性使用
        // 一旦调用了 result.subscribe();，spring 底层就不能再把得到的 result 再次使用stream了，所以会报错
        result.subscribe();
        return result;
    }

    /**
     * Flux : 返回0-n个元素
     * 注：需要指定MediaType
     * @return
     */
    @GetMapping(value = "/flux4", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiOperation("flux4 测试")
    private Flux<String> flux4() {

        List list = new ArrayList();
        list.add(1);
        list.add("a");
        list.add("asd");

        Iterator iterator = list.iterator();


        Flux flux = Flux.fromIterable(() -> {
            log.info("12123243453434");
            return iterator;
        });

        // Flux 里面是个stream，而 Flux.subscribe 里面会使用stream，stream 有一个特点就是一次性使用
        // 一旦调用了 result.subscribe();，spring 底层就不能再把得到的 result 再次使用stream了，所以会报错
//        flux.subscribe();
        return flux;
    }







    /*----------------------------------------------*/

    @GetMapping("/")
    @ApiOperation("index 测试")
    public Mono<String> index(final MockWebSession session) {

//        Mono<String> stringMono = session.changeSessionId()
//                .then(thenTask1())
//                .then(thenTask2())
//                .thenReturn(thenReturnTask());


        Mono<String> stringMono1 = Mono.fromRunnable(() -> {
            log.info("Performing then task 0");
        }).then(thenTask1())
                .then(thenTask2())
                .thenReturn(thenReturnTask());


        return stringMono1;
    }

    private Mono<Void> thenTask1() {
        return Mono.create(monoSink -> {
            System.out.println("Performing then task 1");
            monoSink.success();
        });
    }

    private Mono<Void> thenTask2() {
        return Mono.create(sink -> {
            System.out.println("Performing then task 2");
            sink.success();
        });
    }

    private String thenReturnTask() {
        System.out.println("Performing then return task");
        return "Welcome to this example";
    }


}
